package eu.whowie.bluecontrol.player;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import eu.whowie.bluecontrol.player.VlcFSM.Events;

public class VlcFSM {
	private final Logger logger = LoggerFactory.getLogger(VlcFSM.class);

	public static enum Events {
		SHUTDOWN("shutdown"), ERROR(null), TEST("help"),
		/* when vlc succesfully starts */INITIALIZED();
		String cmd;

		Events() {
			cmd = null;
		}

		Events(String cmdName) {
			cmd = cmdName;
		}

		String getCmd() {
			return cmd;
		}

		@Override
		public String toString() {
			return cmd;
		}
	};

	private final VlcHandler vlc;
	private State currentState;

	public VlcFSM(VlcHandler vlc) {
		this.vlc = vlc;
		currentState = new StartedState(vlc);
	}

	public void process(Events event) {
		logger.debug("current state: {}, processing event: {}", currentState,
				event);
		if (currentState instanceof ErrorState) {
			throw new IllegalStateException("got cmd when in ERROR state");
		}
		currentState = currentState.process(event);
		logger.debug("final state: {}", currentState);
	}

	public Object getCurrentState() {
		return currentState;
	}
}

abstract class State {
	protected Logger logger = LoggerFactory.getLogger(getClass());
	private final VlcHandler handler;

	public State(VlcHandler handler) {
		this.handler = handler;

	}

	public VlcHandler getHandler() {
		return handler;
	}

	abstract State process(VlcFSM.Events event);

}

class ErrorState extends State {

	public ErrorState(VlcHandler handler) {
		super(handler);
	}

	@Override
	public State process(Events event) {
		throw new IllegalStateException(
				"cant process any events in Error State");
	}

}

class StartedState extends State {

	public StartedState(VlcHandler handler) {
		super(handler);
	}

	@Override
	public State process(Events event) {
		logger.debug("processing event {}", event);

		switch (event) {
		case INITIALIZED:
			return new ReadyState(getHandler());
		default:
			logger.warn("unimplemented event handling: " + event);
			return this;
		}
	}

	@Override
	public String toString() {
		return "STARTING";
	}
}

class ReadyState extends State {

	public ReadyState(VlcHandler handler) {
		super(handler);
		handler.setReady(true);
		handler.runCmd("help");
	}

	@Override
	State process(Events event) {
		switch (event) {
		case SHUTDOWN:
			return new ShuttingDownEvent(getHandler());
		default:
			logger.warn("unimplemented event handling: " + event);
			return this;
		}
	}

	@Override
	public String toString() {
		return "READY";
	}
}

class ShuttingDownEvent extends State {

	public ShuttingDownEvent(VlcHandler handler) {
		super(handler);
		handler.runCmd("quit");
	}

	@Override
	State process(Events event) {
		logger.debug("processing event {}", event);

		switch (event) {

		default:
			logger.warn("unimplemented event handling: " + event);
			return this;
		}
	}

	@Override
	public String toString() {
		return "SHUTTING DOWN";
	}
}
